from picshell.engine.util.Format import Format
from picshell.engine.util import BitUtil
from picshell.engine.core.Inst import Inst


#
# 14 bit Mnemonic set (16F877, 16F876, 16F628 ...)
#

# DC si la somme des quatre bits de poids faible est > 15 ( DC=1 ) 
# http://p.may.chez-alice.fr/instructions2.html

def ADDLW( st, inst):
    k = inst.value
    w = st.getW() + k;
    st.setC((w>255));
    w = w&0xff
    st.setZ((w == 0));
    st.setW(w&0xFF);
    return False

def ADDWF(st, inst):
    val = st.regRead(inst.value)
    res = (st.getW() + (val&0xFF))
    pclModified =False;
    
    st.setZ(((res& 0xff) == 0));
    st.setC((res > 255));
    res = res & 0xff; # convert to unsigned byte
    # TODO : DC
    if (inst.dest == Inst.DEST_W):
      st.setW(res);
    elif (inst.dest == Inst.DEST_F):
      pclModified = st.regWrite(inst.value, res);
    return pclModified;

def ANDLW( st,  inst):
    k = inst.value;
    w = st.getW() & k;
    w=w&255
    st.setW(w);
    st.setZ((w == 0));
    return False
 
def BCF( st,  inst) :
    return  st.regWrite(inst.value, st.regRead(inst.value) & inst.inv_bit);

def BSF( st,  inst):
    val = st.regRead(inst.value)
    bit = 1
    bit = bit << inst.bit
    val = val | bit
    pclModified = st.regWrite(inst.value,val)
    return pclModified;

def BTFSC(  st,  inst):
    val = st.regRead(inst.value)
    bval = inst.bit;
    if ((inst.value== 3)and (bval==1)) :
        Format.dumpInstruction(inst);
        print("DC carry not supported yet");
    elif (BitUtil.isClear(val, bval)):
        st.incPc(); # skip next
    return False;

def BTFSS( st,  inst):
    val = st.regRead(inst.value);
    bval = inst.bit
    if ((inst.value== 3)and (bval==1)):
        Format.dumpInstruction(inst);
        print("DC carry not supported yet");
    elif (BitUtil.isSet(val, bval)):
        st.incPc(); # skip next
    return False;

def CALL( st,  inst):
    st.pushStack()
    st.changePcForCallGoto(inst.value)
    return True


def CLRF( st,  inst):
    pclModified = st.regWrite(inst.value, 0)
    st.setZ(True)
    return pclModified


def DECF( st,  inst):
    val = st.regRead(inst.value);
    res = val-1;
    pclModified =False;
    res = res & 0xff; # convert to unsigned byte
    st.setZ((res == 0));
   
    if (inst.dest == Inst.DEST_W):
        st.setW(res)
    elif (inst.dest == Inst.DEST_F):
        pclModified = st.regWrite(inst.value, res)
    return pclModified;

    
def DECFSZ( st,  inst):
    val = (st.regRead(inst.value) - 1) & 0xff;
    pclModified = st.regWrite(inst.value, val)
    if (val == 0):
        st.incPc();
    return pclModified;

    
def GOTO( st,  inst):
    st.changePcForCallGoto(inst.value);
    return True;

    
def INCF( st,  inst):
    pclModified = False;
    val = st.regRead(inst.value);
    res = val + 1;
    res = res & 0xff; # convert to unsigned byte
    st.setZ((res == 0));
    
    # TODO : DC
    if (inst.dest == Inst.DEST_W):
        st.setW(res); 
    elif (inst.dest == Inst.DEST_F):
        pclModified = st.regWrite(inst.value, res);
    return pclModified;
 
    
def IORLW( st,  inst):
    k = inst.value;
    w = st.getW() | k;
    w = w&0xff
    st.setZ(w == 0);
    st.setW(w);
    return False;

    
def IORWF( st,  inst):
    pclModified = False
    val = st.regRead(inst.value);
    res = st.getW() | val;
    res = res & 0xff; # convert to unsigned byte
    st.setZ((res == 0));
    
    if (inst.dest == Inst.DEST_F):
        pclModified = st.regWrite(inst.value, res);
    elif (inst.dest == Inst.DEST_W):
        st.setW(res);
    return pclModified;

    
def MOVF( st,  inst):
    val = st.regRead(inst.value)
    st.setZ((val==0)) 
    if (inst.dest == Inst.DEST_W):
       st.setW(val);
    return False;

    
def MOVLW( st,  inst):
    st.setW(inst.value)
    return False;


def MOVWF( st,  inst):
    pclModified = st.regWrite(inst.value,st.getW())
    return pclModified;


def NOP(st,inst):
    return False;

    
def RETLW( st,  inst):
    pc = st.popStack()
    st.setW(inst.value)
    st.setPc(pc)
    return False


def RETURN( st,  inst):
    pc = st.popStack();
    st.setPc(pc);
    return False

    
def RLF( st,  inst):
    val = st.regRead(inst.value);
    res = (val&0xFF)<<1;
    pclModified = False;
    saveCarry = st.getC();
    st.setC((res > 255));
    res = res & 0xff; # convert to unsigned byte
    if(saveCarry):
        res |=1;
    
    if (inst.dest == Inst.DEST_W):
        st.setW(res);
    elif (inst.dest == Inst.DEST_F):
        pclModified = st.regWrite(inst.value, res);
    return pclModified;
        
    
def SLEEP( st,  inst):
    return False;

    
def SUBLW( st,  inst):
    k = inst.value;
    w = k - st.getW();
    st.setZ(((w&255) == 0));
    st.setC((w<0));
    st.setW(w&0xFF);
    return False
 
    
def SUBWF( st,  inst):
    pclModified = False;
    val = st.regRead(inst.value);
    res = (val&0xFF) - st.getW();
    st.setZ(((res&255) == 0));
    
    # if w < Y: Status,Z = 0. Status,C = 1.
    # if w == Y: Status,Z = 1. Status,C = 1. wnew = 0.
    # if Y < w: Status,Z = 0. Status,C = 0. wnew = Y-w + 0x100. 
    
    st.setC(True);
    if (val < st.getW()):
        st.setC(False);
        
    
    res = res & 0xff; # convert to unsigned byte
    # TODO : DC
    if (inst.dest == Inst.DEST_W):
        st.setW(res); 
    elif (inst.dest == Inst.DEST_F) :
        pclModified = st.regWrite(inst.value, res);
    return pclModified; 
 
    
def SWAPF( st,  inst):
    pclModified = False;
    val = st.regRead(inst.value);
    lowbits = val & 0X0F;
    highbits = val & 0XF0;
    lowbits = lowbits << 4;
    highbits = highbits >> 4;
    if (inst.dest == Inst.DEST_F):
        pclModified = st.regWrite(inst.value, lowbits + highbits);
    elif (inst.dest == Inst.DEST_W) :
        st.setW(lowbits + highbits);
    return pclModified;
        
    
def CLRWDT( st,  inst):
    return False;
    
    
def CLRW( st,  inst):
    st.setW(0);
    st.setZ(True)
    return False;
   
    
def ANDWF( st,  inst):
    pclModified = False
    val = st.regRead(inst.value);
    res = st.getW() & val;
    res = res & 0xff; # convert to unsigned byte
    st.setZ((res == 0));
    
    if (inst.dest == Inst.DEST_F):
        pclModified = st.regWrite(inst.value, res);
    elif (inst.dest == Inst.DEST_W):
        st.setW(res);
    return pclModified;   
   
    
def COMF( st,  inst):
    pclModified = False
    val = st.regRead(inst.value);
    res =  val ^0xFF; # do the comp (each byte are inverted)
    res = res & 0xff; # convert to unsigned byte
    st.setZ((res == 0));
    
    if (inst.dest == Inst.DEST_F):
        pclModified = st.regWrite(inst.value, res);
    elif (inst.dest == Inst.DEST_W):
        st.setW(res);
    return pclModified;   
   
    
    
def INCFSZ( st,  inst):
    pclModified = False
    val = (st.regRead(inst.value) + 1) & 0xff;
    if (inst.dest == Inst.DEST_W):
        st.setW(val); 
    elif (inst.dest == Inst.DEST_F):
        pclModified = st.regWrite(inst.value, val);
    
    if (val == 0):
        st.incPc();
    return pclModified;


    
def RRF( st,  inst):
    val = st.regRead(inst.value);
    nextCarry = val & 1
    res = val>>1;
    if (st.getC()):
         res |=128; # bit 7
    if(nextCarry>0):
        st.setC(True)
    else:
        st.setC(False)
    pclModified = False;
    res = res & 0xff; # convert to unsigned byte
    if (inst.dest == Inst.DEST_W):
        st.setW(res);
    elif (inst.dest == Inst.DEST_F):
        pclModified = st.regWrite(inst.value, res);
    return pclModified;
    
    
def XORLW( st,  inst):
    k = inst.value;
    w = st.getW() ^ k;
    w = w&255
    st.setZ(w == 0);
    st.setW(w&0xFF);
    return False;

    
def XORWF( st,  inst):
    pclModified = False
    val = st.regRead(inst.value);
    res = st.getW() ^ val;
    res = res & 0xff; # convert to unsigned byte
    st.setZ((res == 0));
    
    if (inst.dest == Inst.DEST_F):
        pclModified = st.regWrite(inst.value, res);
    elif (inst.dest == Inst.DEST_W):
        st.setW(res);
    return pclModified;
   